package de.mmis.core.infrastructure;

import static de.mmis.core.infrastructure.Message.MessageType.*;

import java.net.InetAddress;
import java.net.UnknownHostException;

import de.mmis.core.base.Annotations.NoProperty;
import de.mmis.core.base.abstracttree.Tree;
import de.mmis.core.base.infrastructure.InfrastructureEvent;
import de.mmis.core.base.infrastructure.PublishedDeviceDescription;
import de.mmis.core.sexpression.SExpressionWriter;

public class Message {

	public static enum MessageType {
		HELLO,

		/** change bind address */
		REBIND,

		/** search for a device */
		SEARCH,

		ADD, REMOVE,

		/** transmit this event */
		EVENT
	}

	static Message hello(InetAddress address) {
		Message result = new Message(HELLO);
		result.address = address;
		return result;
	}

	static Message rebind(InetAddress address) {
		Message result = new Message(REBIND);
		result.address = address;
		return result;
	}

	static Message addDevice(PublishedDeviceDescription device, boolean existing) {
		Message result = new Message(ADD);
		result.device = device;
		result.addExisting = existing;
		return result;
	}

	static Message removeDevice(PublishedDeviceDescription device) {
		Message result = new Message(REMOVE);
		result.device = device;
		return result;
	}

	static Message searchDevice(PublishedDeviceDescription pattern, Tree id) {
		Message result = new Message(SEARCH);
		result.device = pattern;
		result.ID = id;
		return result;
	}

	static Message event(InfrastructureEvent event) {
		Message result = new Message(EVENT);
		result.event = event;
		return result;
	}

	private MessageType type = null;
	private InfrastructureEvent event = null;
	/** the device or search pattern, if needed */
	private PublishedDeviceDescription device = null;

	/** add new or add existing device */
	private boolean addExisting;
	/** machine migrated / removed clean or dirty */
	private boolean clean;
	/** ID of search query */
	private Tree ID;
	private InetAddress address;

	/**
	 * @deprecated should only be used by deserializer
	 */
	@Deprecated
	public Message() {
		// nothing
	}

	public Message(MessageType command) {
		this.type = command;
	}

	@Override
	public String toString() {
		byte[] b = SExpressionWriter.writeSExpression(Tree.fromObject(this));
		return new String(b);
	}

	public PublishedDeviceDescription getDevice() {
		return device;
	}

	public void setDevice(PublishedDeviceDescription device) {
		this.device = device;
	}

	public boolean isAddExisting() {
		return addExisting;
	}

	public void setAddExisting(boolean addExisting) {
		this.addExisting = addExisting;
	}

	public boolean isClean() {
		return clean;
	}

	public void setClean(boolean clean) {
		this.clean = clean;
	}

	public Tree getID() {
		return ID;
	}

	public void setID(Tree iD) {
		ID = iD;
	}

	public MessageType getType() {
		return type;
	}

	public void setType(MessageType type) {
		this.type = type;
	}

	public InfrastructureEvent getEvent() {
		return event;
	}

	public void setEvent(InfrastructureEvent event) {
		this.event = event;
	}

	public String getAddressS() {
		if (address == null)
			return null;
		return address.getHostAddress();
	}

	public void setAddressS(String address) {
		if (address == null) {
			this.address = null;
			return;
		}
		try {
			this.address = InetAddress.getByName(address);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
	}

	/**
	 * this is annotated with &#64;NoProperty, since {@link InetAddress} is not
	 * deserializable. For (de)serialization, {@link #getAddressS()} is used,
	 * which use the string representation.
	 */
	@NoProperty
	public InetAddress getAddress() {
		return address;
	}

}
